package edu.uwm.cs552;

import java.awt.Graphics;
import java.awt.Point;
import java.util.NoSuchElementException;

import edu.uwm.cs552.util.FormatException;
import edu.uwm.cs552.util.Pair;

/**
 * The edge of a hexagon on a hexagonal game board.
 * Note that each edge is the edge of two different hexagons (in opposite directions).
 */
public class HexEdge {

	private final HexCoordinate base;
	private final HexDirection direction;
	
	/**
	 * Create an edge for a hexagonal grid hexagon.
	 * This edge will be equal to one created using the other hexagon
	 * with the opposite direction.
	 * @param base the hexagon the edge is for
	 * @param direction2 one of the six directions.
	 */
	public HexEdge(HexCoordinate base2, HexDirection direction2) {
		base = base2;
		direction = direction2;
	}
	
	public static final HexEdge ORIGIN = new HexEdge(HexCoordinate.ORIGIN, HexDirection.EAST);

	public double a() { return base.a() + 0.5 * direction.da(); }
	public double b() { return base.b() + 0.5 * direction.db(); }
	
	private HexCoordinate getDual() {
		return base.move(direction);
	}
	
	@Override 
	public String toString() {
		return base + "@" + direction;
	}
	
	public static HexEdge fromString(String s) throws FormatException {
		int at = s.indexOf('@');
		if (at <= 0) throw new FormatException("HexEdge requires @ separator: " + s);
		try {
			return new HexEdge(HexCoordinate.fromString(s.substring(0,at)),
					HexDirection.valueOf(s.substring(at+1)));
		} catch (NoSuchElementException e) {
			throw new FormatException(e);
		}
	}
	
	@Override
	public boolean equals(Object x) {
		if (!(x instanceof HexEdge)) return false;
		HexEdge o = (HexEdge)x;
		if (o.base.equals(base) && o.direction == direction) return true;
		if (o.base.equals(getDual()) && o.direction == direction.reverse()) return true;
		return false;
	}
	
	@Override
	public int hashCode() {
		return (int)(a()*2) *197 + (int)(b()*2);
	}
	
	public Pair<Point,Point> toLineSegment(double scale) {
		HexDirection next = direction.nextClockwise();
		HexDirection prev = direction.nextCounterClockwise();
		double a1 = base.a() + (prev.da() + direction.da())/3.0;
		double b1 = base.b() + (prev.db() + direction.db())/3.0;
		double a2 = base.a() + (next.da() + direction.da())/3.0;
		double b2 = base.b() + (next.db() + direction.db())/3.0;
		final Point p1 = HexCoordinate.toPoint(a1, b1, scale);
		final Point p2 = HexCoordinate.toPoint(a2, b2, scale);
		return new Pair<Point,Point>(p1,p2);
	}
	
	public void draw(Graphics g, double scale) {
		Pair<Point,Point> pp = toLineSegment(scale);
		g.drawLine(pp.fst.x, pp.fst.y, pp.snd.x, pp.snd.y);
	}
	
	private static final double SQRT32 = Math.sqrt(3)/2;
	
	public static HexEdge fromPoint(Point p, double scale, double bound) {
		HexCoordinate base = HexCoordinate.fromPoint(p,scale);
		double b = p.y / scale / SQRT32;
		double a = p.x / scale + b / 2;
		double da = a - base.a();
		double db = b - base.b();
		HexDirection direction = HexDirection.fromDelta(da,db);
		HexEdge he =  new HexEdge(base,direction);
		
		double da2 = Math.abs(he.a()-a);
	    double db2 = Math.abs(he.b()-b);
	    double dc2 = Math.abs((he.a()-he.b())-(a-b));
	    if((da2 + db2 + dc2) <= bound) {
	    	return he;
	    }
	    return null;
	}

	public Pair<HexCoordinate, HexCoordinate> getHexagons() {
		return new Pair<HexCoordinate, HexCoordinate>(base, getDual());
	}

}
